#ifndef __BLOCKING_QUEUE_HPP__
#define __BLOCKING_QUEUE_HPP__
// 基于阻塞队列的生产者消费者模型

#include "./MutexGuard.hpp"

template<class T>
class BlockQueue
{
public:

    // 基于生产者消费者实现的阻塞队列，可重入对象
    // 基本思想：
    // 1.push 生产者生产数据，相互之间互斥
    // 2.pop 消费者消费数据，相互之间互斥
    // 生产者与消费者之间需要互斥(消费者不干扰生产者的生产过程)，需要同步(进行通知)
    BlockQueue(size_t capacity = 1024)
    :_capacity(capacity)
    {
        _queue = new std::queue<T>();
        // 初始化互斥锁和同步变量
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_full, nullptr);
        pthread_cond_init(&_empty, nullptr);
    }
    BlockQueue(const BlockQueue&) = delete;

    // 析构函数
    ~BlockQueue()
    {
        // 释放互斥锁和同步变量
        delete _queue;
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_full);
        pthread_cond_destroy(&_empty);
    }

    // 生产者-入队列
    void Push(const T& val)
    {
        // 访问临界资源
        MutexGuard mutex(&_mutex);  // 上锁
        while(_capacity == _queue->size()) pthread_cond_wait(&_full, &_mutex);// 检查队列是否满，满了等待消费者发出可以消费的信息
        // 此时可以生产
        _queue->push(val);
        // 生产完一份可以通知消费者消费了
        pthread_cond_signal(&_empty);
    }

    // 消费者-出队列
    T Pop()
    {
        MutexGuard mutex(&_mutex);  // 上锁
        while(0 == _queue->size()) pthread_cond_wait(&_empty, &_mutex);
        T val = _queue->back();
        _queue->pop();   // 弹出
        pthread_cond_signal(&_full);
        return val;
    }

private:
    size_t _capacity;  // 阻塞队列的容量
    std::queue<T>* _queue;// 不可重入对象 std标准库中的队列
    pthread_mutex_t _mutex;  // 互斥锁
    pthread_cond_t _full;// 同步变量 满的情况下由消费者消费了通知
    pthread_cond_t _empty; // 同步变量 空的情况下由生产者生产了通知
};

#endif